package com.kettle;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;

public class EasyExcelUtil {

	public static void main(String[] args) throws Throwable {
		long startTime = System.currentTimeMillis(); // 获取开始时间
		String v_sheetName = "";// 读取sheet名称，为空表示所有sheet "销售应收款表,客户基本信息表";
		String v_filePath_string = "E:\\Excel\\excel_string.xlsx";// 原始文件路径
		String v_filePath_string_file = "E:\\Excel\\excel_string_out.xlsx";// 通过String写入文件名
		String v_filePath_string_path = "E:\\Excel\\";// 通过String写入单个文件路径
		String v_filePath_model = "E:\\Excel\\excel_model.xlsx";// 原始文件路径
		String v_filePath_model_file = "E:\\Excel\\excel_model_out.xlsx";// 通过Model写入文件名
		String v_filePath_model_path = "E:\\Excel\\";// 通过Model写入单个文件路径
		Files.createParentDirs(new File(v_filePath_string));// 创建文件夹

		// 通过String类,读取Demo数据并写入到一个Excel,参数：sheetNum工作表数,rowNum行数,colNum列数
		Map<String, List<List<String>>> dataListMap1 = EasyExcelUtil.getDemoDataByString(1, 104 * 10000, 10);
		EasyExcelUtil.WriteExcelByString(v_filePath_string, dataListMap1);

		// 通过String类,将多个sheet写入到一个Excel
		 Map<String, List<List<String>>> dataListMap2 = EasyExcelUtil.ReadExcelByString(v_filePath_string, v_sheetName);
		 EasyExcelUtil.WriteExcelByString(v_filePath_string_file, dataListMap2);

		// 通过String类,将一个sheet写入到一个Excel
		// Map<String, List<List<String>>> dataListMap3 = EasyExcelUtil.ReadExcelByString(v_filePath_string, v_sheetName);
		// for (Entry<String, List<List<String>>> entry : dataListMap3.entrySet()) {
		// String sheetName = entry.getKey();// 得到工作表名称
		// List<List<String>> dataList = entry.getValue();// 得到工作表数据
		// String filePath = v_filePath_string_path + sheetName + ".xlsx";// 指定文件路径
		// Files.createParentDirs(new File(filePath));// 创建文件夹
		// WriteExcelByString(filePath, sheetName, dataList);// 输出Excel文件
		// System.out.println(sheetName + ":" + dataList.size());
		// }

		// 通过Model类,,读取Demo数据并写入到一个Excel,参数：sheetNum工作表数,rowNum行数
		// Map<String, List<BaseRowModel>> dataListMap4 = EasyExcelUtil.getDemoDataByModel(5, 104 * 10000);
		// EasyExcelUtil.WriteExcelByModel(v_filePath_model, dataListMap4, BaseExcelBean.class);

		// 通过Model类,将多个sheet写入到一个Excel
		// Map<String, List<BaseRowModel>> dataListMap5 = EasyExcelUtil.ReadExcelByModel(v_filePath_model, v_sheetName, BaseExcelBean.class);
		// EasyExcelUtil.WriteExcelByModel(v_filePath_model_file, dataListMap5, BaseExcelBean.class);

		// 通过Model类,将一个sheet写入到一个Excel
		// Map<String, List<BaseRowModel>> dataListMap6 = EasyExcelUtil.ReadExcelByModel(v_filePath_model, v_sheetName, BaseExcelBean.class);
		// for (Entry<String, List<BaseRowModel>> entry : dataListMap6.entrySet()) {
		// String sheetName = entry.getKey();// 得到工作表名称
		// List<BaseRowModel> dataList = entry.getValue();// 得到工作表数据
		// String filePath = v_filePath_model_path + sheetName + ".xlsx";// 指定文件路径
		// Files.createParentDirs(new File(filePath));// 创建文件夹
		// WriteExcelByModel(filePath, sheetName, dataList, BaseExcelBean.class);// 输出Excel文件
		// System.out.println(sheetName + ":" + dataList.size());
		// }

		long endTime = System.currentTimeMillis(); // 获取结束时间
		System.out.println((endTime - startTime) / 1000.0);
	}

	/**
	 * 通过String类,读取工作表数据
	 */
	public static Map<String, List<List<String>>> ReadExcelByString(String v_filePath) {
		return ReadExcelByString(v_filePath, null);
	}

	/**
	 * 通过String类,读取工作表数据
	 */
	public static Map<String, List<List<String>>> ReadExcelByString(String v_filePath, String v_sheetName) {
		Map<String, List<List<String>>> dataListMap = Maps.newLinkedHashMap();// 创建返回信息
		StringExcelListener excelListener = new StringExcelListener();// 解析监听器
		try {
			InputStream inputStream = new FileInputStream(v_filePath);// 创建文件流
			ExcelReader excelReader = EasyExcelFactory.getReader(inputStream, excelListener);
			List<Sheet> sheets = excelReader.getSheets();// 得到所有工作表
			for (Sheet sheet : sheets) {// 取所有工作表数据
				String sheetName = sheet.getSheetName();// 工作表名称
				// 没有指定工作表，或多个工作表
				if (Strings.isNullOrEmpty(v_sheetName) || Splitter.on(',').trimResults().omitEmptyStrings().splitToList(v_sheetName).contains(sheetName)) {
					excelReader.read(sheet);// 读取Excel数据
					List<List<String>> sheetDataInfo = Lists.newArrayList(excelListener.getDataList());// 返回明细数据
					dataListMap.put(sheetName, sheetDataInfo);// 将工作表数据放入工作薄
					excelListener.clear();// 清除缓存数据
				}
			}
			// 关闭文件流
			inputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return dataListMap;
	}

	/**
	 * 通过Model类,读取工作表数据
	 */
	public static Map<String, List<BaseRowModel>> ReadExcelByModel(String v_filePath, Class<? extends BaseRowModel> clazz) {
		return ReadExcelByModel(v_filePath, null, clazz);
	}

	/**
	 * 通过Model类,读取工作表数据
	 */
	public static Map<String, List<BaseRowModel>> ReadExcelByModel(String v_filePath, String v_sheetName, Class<? extends BaseRowModel> clazz) {
		// 解析每行结果在listener中处理
		Map<String, List<BaseRowModel>> dataListMap = Maps.newLinkedHashMap();// 创建返回信息
		ModelExcelListener excelListener = new ModelExcelListener();// 解析监听器
		try {
			InputStream inputStream = new FileInputStream(v_filePath);// 创建文件流
			ExcelReader excelReader = EasyExcelFactory.getReader(inputStream, excelListener);
			List<Sheet> sheets = excelReader.getSheets();// 得到所有工作表
			for (Sheet sheet : sheets) {// 取所有工作表数据
				String sheetName = sheet.getSheetName();// 工作表名称
				if (Strings.isNullOrEmpty(v_sheetName) || Splitter.on(',').trimResults().omitEmptyStrings().splitToList(v_sheetName).contains(sheetName)) {
					sheet.setClazz(clazz);// 设置模板
					excelReader.read(sheet);// 读取Excel数据
					List<BaseRowModel> sheetDataInfo = Lists.newArrayList(excelListener.getDataList());// 返回明细数据
					dataListMap.put(sheetName, sheetDataInfo); // 将工作表数据放入工作薄
					excelListener.clear();// 清除缓存数据
				}
			}
			// 关闭文件流
			inputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return dataListMap;
	}

	/**
	 * 通过String类,将一个sheet写入到一个Excel
	 */
	public static void WriteExcelByString(String v_filePath, String v_sheetName, List<List<String>> dataList) {
		Map<String, List<List<String>>> dataListMap = Maps.newLinkedHashMap();// 创建返回信息
		dataListMap.put(v_sheetName, dataList);// 将工作表放入到Excel中
		WriteExcelByString(v_filePath, dataListMap);// 输出Excel数据
	}

	/**
	 * 通过String类,将多个sheet写入到一个Excel
	 */
	public static void WriteExcelByString(String v_filePath, Map<String, List<List<String>>> dataListMap) {
		try {
			int sheetNo = 1;// 工作表编号
			OutputStream out = new FileOutputStream(v_filePath);// 创建文件流
			ExcelWriter writer = EasyExcelFactory.getWriter(out);
			// 循环写入每个工作表
			for (Entry<String, List<List<String>>> entry : dataListMap.entrySet()) {
				String sheetName = entry.getKey();// 得到工作表名称
				List<List<String>> dataList = entry.getValue();// 得到工作表数据
				Sheet sheet1 = new Sheet(sheetNo++, 1, null, sheetName, null);// 设置工作表信息
				sheet1.setStartRow(-1);// 设置开始行为-1
				sheet1.setAutoWidth(Boolean.TRUE);// 设置自适应宽度
				writer.write0(dataList, sheet1);// 开始写数据
			}
			writer.finish();// 清空缓存
			out.close();// 关闭文件
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 通过Model类,将一个sheet写入到一个Excel
	 */
	public static void WriteExcelByModel(String v_filePath, String v_sheetName, List<BaseRowModel> dataList, Class<? extends BaseRowModel> clazz) {
		Map<String, List<BaseRowModel>> dataListMap = Maps.newLinkedHashMap();// 创建返回信息
		dataListMap.put(v_sheetName, dataList);// 将工作表放入到Excel中
		WriteExcelByModel(v_filePath, dataListMap, clazz);// 输出Excel数据
	}

	/**
	 * 通过String类,将多个sheet写入到一个Excel
	 */
	public static void WriteExcelByModel(String v_filePath, Map<String, List<BaseRowModel>> dataListMap, Class<? extends BaseRowModel> clazz) {
		try {
			int sheetNo = 1;// 工作表编号
			OutputStream out = new FileOutputStream(v_filePath);// 创建文件流
			ExcelWriter writer = EasyExcelFactory.getWriter(out);
			// 循环写入每个工作表
			for (Entry<String, List<BaseRowModel>> entry : dataListMap.entrySet()) {
				String sheetName = entry.getKey();// 得到工作表名称
				List<BaseRowModel> dataList = entry.getValue();// 得到工作表数据
				Sheet sheet1 = new Sheet(sheetNo++, 1, clazz, sheetName, null);// 设置工作表信息
				sheet1.setAutoWidth(Boolean.TRUE);// 设置自适应宽度
				writer.write(dataList, sheet1);// 开始写数据
			}
			writer.finish();// 清空缓存
			out.close();// 关闭文件
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * --------------------------------以下为辅助功能--------------------------------
	 * String类,解析监听器
	 */
	private static class StringExcelListener extends AnalysisEventListener<List<String>> {
		// 自定义用于暂时存储data。
		// 可以通过实例获取该值
		private List<List<String>> dataList = Lists.newArrayList();

		public void invoke(List<String> rowInfo, AnalysisContext context) {
			// System.out.println(context.getCurrentRowNum() + ":" + rowInfo);
			dataList.add(rowInfo);// 数据存储到list，供批量处理，或后续自己业务逻辑处理。
		}

		// 解析结束销毁不用的资源
		public void doAfterAllAnalysed(AnalysisContext context) {
			// dataList.clear();//解析结束销毁不用的资源
		}

		// 返回sheet数据
		public List<List<String>> getDataList() {
			return dataList;
		}

		// 设计sheet数据
		public void setDataList(List<List<String>> dataList) {
			this.dataList = dataList;
		}

		// 清空数据
		public void clear() {
			dataList.clear();
		}
	}

	/**
	 * Model类,解析监听器
	 */
	private static class ModelExcelListener extends AnalysisEventListener<BaseRowModel> {
		// 自定义用于暂时存储data。
		// 可以通过实例获取该值
		private List<BaseRowModel> dataList = Lists.newArrayList();

		@Override
		public void invoke(BaseRowModel rowInfo, AnalysisContext context) {
			// System.out.println(context.getCurrentRowNum() + ":" + rowInfo);
			dataList.add(rowInfo);// 数据存储到list，供批量处理，或后续自己业务逻辑处理。
		}

		// 解析结束销毁不用的资源
		@Override
		public void doAfterAllAnalysed(AnalysisContext context) {
			// dataList.clear();//解析结束销毁不用的资源
		}

		// 返回sheet数据
		public List<BaseRowModel> getDataList() {
			return dataList;
		}

		// 设计sheet数据
		public void setDataList(List<BaseRowModel> dataList) {
			this.dataList = dataList;
		}

		// 清空数据
		public void clear() {
			dataList.clear();
		}
	}


	/**
	 * --------------------------------以下为测试数据--------------------------------
	 * 通过String类,生成测试数据
	 */
	private static Map<String, List<List<String>>> getDemoDataByString(int sheetNum, int rowNum, int colNum) {
		Map<String, List<List<String>>> dataListMap = Maps.newLinkedHashMap();
		for (int sheetNo = 1; sheetNo <= sheetNum; sheetNo++) {
			String sheetName = "excel_string_out_第" + sheetNo + "个表";// 得到工作表名称
			List<List<String>> dataList = Lists.newArrayList();// 得到工作表数据
			for (int rowNo = 1; rowNo <= rowNum; rowNo++) {
				List<String> dataInfo = Lists.newArrayList();// 得到行数据
				for (int colNo = 1; colNo <= colNum; colNo++) {
					String cellValue = "第" + sheetNo + "表," + rowNo + "行," + colNo + "列";// 单元格值
					dataInfo.add(cellValue);// 添加值
				}
				dataList.add(dataInfo);// 添加行
			}
			dataListMap.put(sheetName, dataList);// 添加工作表
		}
		return dataListMap;
	}

	/**
	 * 通过Model类,生成测试数据
	 */
	private static Map<String, List<BaseRowModel>> getDemoDataByModel(int sheetNum, int rowNum) {
		Map<String, List<BaseRowModel>> dataListMap = Maps.newLinkedHashMap();
		for (int sheetNo = 1; sheetNo <= sheetNum; sheetNo++) {
			String sheetName = "excel_model_out_第" + sheetNo + "个表";// 得到工作表名称
			List<BaseRowModel> dataList = Lists.newArrayList();// 得到工作表数据
			for (int rowNo = 1; rowNo <= rowNum; rowNo++) {
				BaseExcelBean dataInfo = new BaseExcelBean();// 得到行数据
				dataInfo.setCol1("第" + sheetNo + "表," + rowNo + "行,1列");
				dataInfo.setCol2("第" + sheetNo + "表," + rowNo + "行,2列");
				dataInfo.setCol3("第" + sheetNo + "表," + rowNo + "行,3列");
				dataInfo.setCol4("第" + sheetNo + "表," + rowNo + "行,4列");
				dataInfo.setCol5("第" + sheetNo + "表," + rowNo + "行,5列");
				dataList.add(dataInfo);// 添加行
			}
			dataListMap.put(sheetName, dataList);// 添加工作表
		}
		return dataListMap;
	}
}
